﻿using System;
using System.Linq;
using System.ComponentModel;
using Moria.Common.Enum;
using Redbrick.Silverlight.Common;
using System.Collections.Generic;

namespace Moria.Common.Model
{



	public class Player : Drawable
	{
		#region Consts & Settings

		public const int MaxLevel = 40;     // was MAX_PLAYER_LEVEL
		public const int WeightCap = 130;   // "#"*(1/10 pounds) per strength point
		public const int BTH_PLUS_ADJ = 3;  // Adjust BTH per plus-to-hit

		#endregion Consts & Settings

		#region Declarations

		// InventoryCollection _this.inventory = new InventoryCollection();
		bool weapon_heavy = false;
		int spell_learned = 0;
		int spell_forgotten = 0;
		int[] spell_order = new int[32];
		int[] player_hp = null;
		bool _findFlag = false;
		int _commandCount = 0;

		string _name;
		Gender _gender = Gender.Unknown;
		int _invenWeight = 0;
		int _au = 0;
		int _max_exp;
		int _exp;
		int _exp_frac;
		int _age;
		int _ht;
		int _wt;
		int _lev;
		int _max_dlv;
		int _srh;
		int _fos;
		int _bth;
		int _bthb;
		int _mana;
		int _mhp;
		int _ptohit;
		int _ptodam;
		int _pac;
		int _ptoac;
		int _dis_th;
		int _dis_td;
		int _dis_ac;
		int _dis_tac;
		int _disarm;
		int _save;
		int _sc;
		int _stl;
		int _pclass = -1;
		Class _class;
		int _prace = -1;
		Race _race;
		int _hitdie;
		int _expfact;
		int _cmana;
		int _cmana_frac;
		int _chp;
		int _chp_frac;
		string _history;
		int _packHeavy = 0;

		StatCollection _max_stat = new StatCollection();
		StatCollection _cur_stat = new StatCollection();
		StatCollection _mod_stat = new StatCollection();
		StatCollection _use_stat = new StatCollection();

		Status _status;
		int _rest;
		int _blind;
		int _paralysis;
		int _confused;
		int _food;
		int _food_digested;
		int _protection;
		int _speed;
		int _fast;
		int _slow;
		int _afraid;
		int _poisoned;
		int _image;
		int _protevil;
		int _invuln;
		int _hero;
		int _shero;
		int _blessed;
		int _resist_heat;
		int _resist_cold;
		int _detect_inv;
		int _word_recall;
		int _see_infra;
		int _tim_infra;
		bool _see_inv;
		bool _teleport;
		bool _free_act;
		bool _slow_digest;
		bool _aggravate;
		bool _fire_resist;
		bool _cold_resist;
		bool _acid_resist;
		bool _regenerate;
		bool _lght_resist;
		bool _ffall;
		bool _sustain_str;
		bool _sustain_int;
		bool _sustain_wis;
		bool _sustain_con;
		bool _sustain_dex;
		bool _sustain_chr;
		int _confuse_monster;
		int _new_spells;

		#region Player Title Table
		//this should live in the Class class 
		private static readonly string[,] player_title = new string[,] 
		{
		#region Warrior	
			{"Rookie","Private","Soldier","Mercenary","Veteran(1st)","Veteran(2nd)","Veteran(3rd)","Warrior(1st)","Warrior(2nd)","Warrior(3rd)","Warrior(4th)",
			 "Swordsman-1","Swordsman-2","Swordsman-3","Hero","Swashbuckler","Myrmidon","Champion-1","Champion-2","Champion-3","Superhero","Knight","Superior Knt",
			 "Gallant Knt","Knt Errant","Guardian Knt","Baron","Duke","Lord (1st)","Lord (2nd)","Lord (3rd)","Lord (4th)","Lord (5th)","Lord (6th)","Lord (7th)",
			 "Lord (8th)","Lord (9th)","Lord Gallant","Lord Keeper","Lord Noble"
			},
		#endregion Warrior
		#region Mage
			{"Novice","Apprentice","Trickster-1","Trickster-2","Trickster-3","Cabalist-1","Cabalist-2","Cabalist-3","Visionist","Phantasmist","Shadowist","Spellbinder",
			 "Illusionist","Evoker (1st)","Evoker (2nd)","Evoker (3rd)","Evoker (4th)","Conjurer","Theurgist","Thaumaturge","Magician","Enchanter","Warlock","Sorcerer",
			 "Necromancer","Mage (1st)","Mage (2nd)","Mage (3rd)","Mage (4th)","Mage (5th)","Wizard (1st)","Wizard (2nd)","Wizard (3rd)","Wizard (4th)","Wizard (5th)",
			 "Wizard (6th)","Wizard (7th)","Wizard (8th)","Wizard (9th)","Wizard Lord"
			},
		#endregion
		#region Priests
			{"Believer","Acolyte(1st)","Acolyte(2nd)","Acolyte(3rd)","Adept (1st)","Adept (2nd)","Adept (3rd)","Priest (1st)","Priest (2nd)","Priest (3rd)",
			 "Priest (4th)","Priest (5th)","Priest (6th)","Priest (7th)","Priest (8th)","Priest (9th)","Curate (1st)","Curate (2nd)","Curate (3rd)","Curate (4th)",
			 "Curate (5th)","Curate (6th)","Curate (7th)","Curate (8th)","Curate (9th)","Canon (1st)","Canon (2nd)","Canon (3rd)","Canon (4th)","Canon (5th)",
			 "Low Lama","Lama-1","Lama-2","Lama-3","High Lama","Great Lama","Patriarch","High Priest","Great Priest","Noble Priest"
			},
		#endregion
		#region Rogues
			{"Vagabond","Footpad","Cutpurse","Robber","Burglar","Filcher","Sharper","Magsman","Common Rogue","Rogue (1st)","Rogue (2nd)","Rogue (3rd)",
			 "Rogue (4th)","Rogue (5th)","Rogue (6th)","Rogue (7th)","Rogue (8th)","Rogue (9th)","Master Rogue","Expert Rogue","Senior Rogue","Chief Rogue",
			 "Prime Rogue","Low Thief","Thief (1st)","Thief (2nd)","Thief (3rd)","Thief (4th)","Thief (5th)","Thief (6th)","Thief (7th)","Thief (8th)",
			 "Thief (9th)","High Thief","Master Thief","Executioner","Low Assassin","Assassin","High Assassin","Guildsmaster"
			},
		#endregion
        #region Rangers
            {"Runner (1st)","Runner (2nd)","Runner (3rd)","Strider (1st)","Strider (2nd)","Strider (3rd)","Scout (1st)","Scout (2nd)","Scout (3rd)","Scout (4th)",
             "Scout (5th)","Courser (1st)","Courser (2nd)","Courser (3rd)","Courser (4th)","Courser (5th)","Tracker (1st)","Tracker (2nd)","Tracker (3rd)",
             "Tracker (4th)","Tracker (5th)","Tracker (6th)","Tracker (7th)","Tracker (8th)","Tracker (9th)","Guide (1st)","Guide (2nd)","Guide (3rd)",
             "Guide (4th)","Guide (5th)","Guide (6th)","Guide (7th)","Guide (8th)","Guide (9th)","Pathfinder-1","Pathfinder-2","Pathfinder-3","Ranger",
             "High Ranger","Ranger Lord"
            },
        #endregion
        #region Paladins
            {"Gallant","Keeper (1st)","Keeper (2nd)","Keeper (3rd)","Keeper (4th)","Keeper (5th)","Keeper (6th)","Keeper (7th)","Keeper (8th)","Keeper (9th)",
             "Protector-1","Protector-2","Protector-3","Protector-4","Protector-5","Protector-6","Protector-7","Protector-8","Defender-1","Defender-2",
             "Defender-3","Defender-4","Defender-5","Defender-6","Defender-7","Defender-8","Warder (1st)","Warder (2nd)","Warder (3rd)","Warder (4th)","Warder (5th)",
             "Warder (6th)","Warder (7th)","Warder (8th)","Warder (9th)","Guardian","Chevalier","Justiciar","Paladin","High Lord"
            }
        #endregion
        };
		#endregion

		#endregion

		#region Constructors

		public Player()
		{
			this.inventory = new InventoryCollection();
			this.IsGenerated = false;
			this.CurrentDungeonLevel = -1;
			_max_stat.StatUpdated += new EventHandler<StatChangedEventArgs>(this.MaxStat_Updated);
			_cur_stat.StatUpdated += new EventHandler<StatChangedEventArgs>(this.CurStat_Updated);
			_mod_stat.StatUpdated += new EventHandler<StatChangedEventArgs>(this.ModStat_Updated);
			_use_stat.StatUpdated += new EventHandler<StatChangedEventArgs>(this.UseStat_Updated);
		}

		#endregion

		#region Properties

		#region Misc
		///<summary>
		/// Name of character	
		///</summary>
		public string name
		{
			get { return _name; }
			set
			{
				if (value == _name) return;
				_name = value;
				this.RaisePropertyChanged(() => this.name);
			}
		}

		public Gender gender
		{
			get { return _gender; }
			set
			{
				if (value == _gender) return;
				_gender = value;
				this.RaisePropertyChanged(() => this.gender);
			}
		}
		///<summary>
		/// Sex of character	
		///</summary>
		public bool isMale
		{
			get { return this.gender == Gender.Male; }
		}
		///<summary>
		/// Gold			
		///</summary>
		public int au
		{
			get { return _au; }
			set
			{
				if (value == _au) return;
				_au = value;
				this.RaisePropertyChanged(() => this.au);
			}
		}
		///<summary>
		/// Max experience	
		///</summary>
		public int max_exp
		{
			get { return _max_exp; }
			set
			{
				if (value == _max_exp) return;
				_max_exp = value;
				this.RaisePropertyChanged(() => this.max_exp);
			}
		}
		///<summary>
		/// Cur experience	
		///</summary>
		public int exp
		{
			get { return _exp; }
			set
			{
				if (value == _exp) return;
				_exp = value;
				this.RaisePropertyChanged(() => this.exp);
			}
		}
		///<summary>
		/// Cur exp fraction * 2^16 
		///</summary>
		public int exp_frac
		{
			get { return _exp_frac; }
			set
			{
				if (value == _exp_frac) return;
				_exp_frac = value;
				this.RaisePropertyChanged(() => this.exp_frac);
			}
		}
		///<summary>
		/// Characters age	
		///</summary>
		public int age
		{
			get { return _age; }
			set
			{
				if (value == _age) return;
				_age = value;
				this.RaisePropertyChanged(() => this.age);
			}
		}
		///<summary>
		/// TileHeight		
		///</summary>
		public int ht
		{
			get { return _ht; }
			set
			{
				if (value == _ht) return;
				_ht = value;
				this.RaisePropertyChanged(() => this.ht);
			}
		}
		///<summary>
		/// Weight		
		///</summary>
		public int wt
		{
			get { return _wt; }
			set
			{
				if (value == _wt) return;
				_wt = value;
				this.RaisePropertyChanged(() => this.wt);
			}
		}
		///<summary>
		/// Level		
		///</summary>
		public int lev
		{
			get { return _lev; }
			set
			{
				if (value == _lev) return;
				_lev = value;
				this.RaisePropertyChanged(() => this.lev);
			}
		}
		///<summary>
		/// Max level explored	
		///</summary>
		public int max_dlv
		{
			get { return _max_dlv; }
			set
			{
				if (value == _max_dlv) return;
				_max_dlv = value;
				this.RaisePropertyChanged(() => this.max_dlv);
			}
		}
		///<summary>
		/// Chance in search	
		///</summary>
		public int srh
		{
			get { return _srh; }
			set
			{
				if (value == _srh) return;
				_srh = value;
				this.RaisePropertyChanged(() => this.srh);
			}
		}
		///<summary>
		/// Frenq of search	
		///</summary>
		public int fos
		{
			get { return _fos; }
			set
			{
				if (value == _fos) return;
				_fos = value;
				this.RaisePropertyChanged(() => this.fos);
			}
		}
		///<summary>
		/// Base to hit		
		///</summary>
		public int bth
		{
			get { return _bth; }
			set
			{
				if (value == _bth) return;
				_bth = value;
				this.RaisePropertyChanged(() => this.bth);
			}
		}
		///<summary>
		/// BTH with bows	
		///</summary>
		public int bthb
		{
			get { return _bthb; }
			set
			{
				if (value == _bthb) return;
				_bthb = value;
				this.RaisePropertyChanged(() => this.bthb);
			}
		}
		///<summary>
		/// Mana points		
		///</summary>
		public int mana
		{
			get { return _mana; }
			set
			{
				if (value == _mana) return;
				_mana = value;
				this.RaisePropertyChanged(() => this.mana);
			}
		}
		///<summary>
		/// Max hit pts		
		///</summary>
		public int mhp
		{
			get { return _mhp; }
			set
			{
				if (value == _mhp) return;
				_mhp = value;
				this.RaisePropertyChanged(() => this.mhp);
			}
		}
		///<summary>
		/// Plusses to hit	
		///</summary>
		public int ptohit
		{
			get { return _ptohit; }
			set
			{
				if (value == _ptohit) return;
				_ptohit = value;
				this.RaisePropertyChanged(() => this.ptohit);
			}
		}
		///<summary>
		/// Plusses to dam	
		///</summary>
		public int ptodam
		{
			get { return _ptodam; }
			set
			{
				if (value == _ptodam) return;
				_ptodam = value;
				this.RaisePropertyChanged(() => this.ptodam);
			}
		}
		///<summary>
		/// Total AC		
		///</summary>
		public int pac
		{
			get { return _pac; }
			set
			{
				if (value == _pac) return;
				_pac = value;
				this.RaisePropertyChanged(() => this.pac);
			}
		}
		///<summary>
		/// Magical AC		
		///</summary>
		public int ptoac
		{
			get { return _ptoac; }
			set
			{
				if (value == _ptoac) return;
				_ptoac = value;
				this.RaisePropertyChanged(() => this.ptoac);
			}
		}
		///<summary>
		/// Display +ToHit	
		///</summary>
		public int dis_th
		{
			get { return _dis_th; }
			set
			{
				if (value == _dis_th) return;
				_dis_th = value;
				this.RaisePropertyChanged(() => this.dis_th);
			}
		}
		///<summary>
		/// Display +ToDam	
		///</summary>
		public int dis_td
		{
			get { return _dis_td; }
			set
			{
				if (value == _dis_td) return;
				_dis_td = value;
				this.RaisePropertyChanged(() => this.dis_td);
			}
		}
		///<summary>
		/// Display +ToAC	
		///</summary>
		public int dis_ac
		{
			get { return _dis_ac; }
			set
			{
				if (value == _dis_ac) return;
				_dis_ac = value;
				this.RaisePropertyChanged(() => this.dis_ac);
			}
		}
		///<summary>
		/// Display +ToTAC	
		///</summary>
		public int dis_tac
		{
			get { return _dis_tac; }
			set
			{
				if (value == _dis_tac) return;
				_dis_tac = value;
				this.RaisePropertyChanged(() => this.dis_tac);
			}
		}
		///<summary>
		/// % to Disarm		
		///</summary>
		public int disarm
		{
			get { return _disarm; }
			set
			{
				if (value == _disarm) return;
				_disarm = value;
				this.RaisePropertyChanged(() => this.disarm);
			}
		}
		///<summary>
		/// Saving throw		
		///</summary>
		public int save
		{
			get { return _save; }
			set
			{
				if (value == _save) return;
				_save = value;
				this.RaisePropertyChanged(() => this.save);
			}
		}
		///<summary>
		/// Social Class		
		///</summary>
		public int sc
		{
			get { return _sc; }
			set
			{
				if (value == _sc) return;
				_sc = value;
				this.RaisePropertyChanged(() => this.sc);
			}
		}
		///<summary>
		/// Stealth factor	
		///</summary>
		public int stl
		{
			get { return _stl; }
			set
			{
				if (value == _stl) return;
				_stl = value;
				this.RaisePropertyChanged(() => this.stl);
			}
		}
		///<summary>
		/// # of class		
		///</summary>
		public int pclass
		{
			get { return _pclass; }
			set
			{
				if (value == _pclass) return;
				_pclass = value;
				this.RaisePropertyChanged(() => this.pclass);
			}
		}

		public Class Class
		{
			get { return _class; }
			private set
			{
				if (value == _class) return;
				_class = value;
				this.RaisePropertyChanged(() => this.Class);
			}
		}
		///<summary>
		/// # of race		
		///</summary>
		public int prace
		{
			get { return _prace; }
			set
			{
				if (value == _prace) return;
				_prace = value;
				this.RaisePropertyChanged(() => this.prace);
			}
		}
		public Race Race
		{
			get { return _race; }
			private set
			{
				if (value == _race) return;
				_race = value;
				this.RaisePropertyChanged(() => this.Race);
			}
		}
		///<summary>
		/// Char hit die		
		///</summary>
		public int hitdie
		{
			get { return _hitdie; }
			set
			{
				if (value == _hitdie) return;
				_hitdie = value;
				this.RaisePropertyChanged(() => this.hitdie);
			}
		}
		///<summary>
		/// Experience factor	
		///</summary>
		public int expfact
		{
			get { return _expfact; }
			set
			{
				if (value == _expfact) return;
				_expfact = value;
				this.RaisePropertyChanged(() => this.expfact);
			}
		}
		///<summary>
		/// Cur mana pts		
		///</summary>
		public int cmana
		{
			get { return _cmana; }
			set
			{
				if (value == _cmana) return;
				_cmana = value;
				this.RaisePropertyChanged(() => this.cmana);
			}
		}
		///<summary>
		/// Cur mana fraction * 2^16 
		///</summary>
		public int cmana_frac
		{
			get { return _cmana_frac; }
			set
			{
				if (value == _cmana_frac) return;
				_cmana_frac = value;
				this.RaisePropertyChanged(() => this.cmana_frac);
			}
		}
		///<summary>
		/// Cur hit pts		
		///</summary>
		public int chp
		{
			get { return _chp; }
			set
			{
				if (value == _chp) return;
				_chp = value;
				this.RaisePropertyChanged(() => this.chp);
			}
		}
		///<summary>
		/// Cur hit fraction * 2^16 
		///</summary>
		public int chp_frac
		{
			get { return _chp_frac; }
			set
			{
				if (value == _chp_frac) return;
				_chp_frac = value;
				this.RaisePropertyChanged(() => this.chp_frac);
			}
		}
		///<summary>
		/// History record	 
		///</summary>
		public string history
		{
			get { return _history; }
			set
			{
				if (value == _history) return;
				_history = value;
				this.RaisePropertyChanged(() => this.history);
			}
		}
		#endregion Misc
		#region Stats

		///<summary>
		/// What is restored 
		///</summary>
		public StatCollection max_stat
		{
			get { return _max_stat; }
			set
			{
				if (value == _max_stat) return;
				_max_stat = value;
				this.RaisePropertyChanged(() => this.max_stat);
			}
		}
		///<summary>
		/// What is natural 
		///</summary>
		public StatCollection cur_stat
		{
			get { return _cur_stat; }
			set
			{
				if (value == _cur_stat) return;
				_cur_stat = value;
				this.RaisePropertyChanged(() => this.cur_stat);
			}
		}
		///<summary>
		/// What is modified, may be +/- 
		///</summary>
		public StatCollection mod_stat
		{
			get { return _mod_stat; }
			set
			{
				if (value == _mod_stat) return;
				_mod_stat = value;
				this.RaisePropertyChanged(() => this.mod_stat);
			}
		}
		///<summary>
		/// What is used 
		///</summary>
		public StatCollection use_stat
		{
			get { return _use_stat; }
			set
			{
				if (value == _use_stat) return;
				_use_stat = value;
				this.RaisePropertyChanged(() => this.use_stat);
			}
		}

		#endregion Stats
		#region Flags
		///<summary>
		/// Status of player    
		///</summary>
		public Status status
		{
			get { return _status; }
			private set
			{
				if (value == _status) return;
				_status = value;
				this.RaisePropertyChanged(() => this.status);
			}
		}
		///<summary>
		/// Rest counter	       
		///</summary>
		public int rest
		{
			get { return _rest; }
			set
			{
				if (value == _rest) return;
				_rest = value;
				this.RaisePropertyChanged(() => this.rest);
			}
		}
		///<summary>
		/// Blindness counter   
		///</summary>
		public int blind
		{
			get { return _blind; }
			set
			{
				if (value == _blind) return;
				_blind = value;
				this.RaisePropertyChanged(() => this.blind);
			}
		}
		///<summary>
		/// Paralysis counter   
		///</summary>
		public int paralysis
		{
			get { return _paralysis; }
			set
			{
				if (value == _paralysis) return;
				_paralysis = value;
				this.RaisePropertyChanged(() => this.paralysis);
			}
		}
		///<summary>
		/// Confusion counter   
		///</summary>
		public int confused
		{
			get { return _confused; }
			set
			{
				if (value == _confused) return;
				_confused = value;
				this.RaisePropertyChanged(() => this.confused);
			}
		}
		///<summary>
		/// Food counter	       
		///</summary>
		public int food
		{
			get { return _food; }
			set
			{
				if (value == _food) return;
				_food = value;
				this.RaisePropertyChanged(() => this.food);
			}
		}
		///<summary>
		/// Food per round      
		///</summary>
		public int food_digested
		{
			get { return _food_digested; }
			set
			{
				if (value == _food_digested) return;
				_food_digested = value;
				this.RaisePropertyChanged(() => this.food_digested);
			}
		}
		///<summary>
		/// Protection fr. evil 
		///</summary>
		public int protection
		{
			get { return _protection; }
			set
			{
				if (value == _protection) return;
				_protection = value;
				this.RaisePropertyChanged(() => this.protection);
			}
		}
		///<summary>
		/// Cur speed adjust    
		///</summary>
		public int speed
		{
			get { return _speed; }
			set
			{
				if (value == _speed) return;
				_speed = value;
				this.RaisePropertyChanged(() => this.speed);
			}
		}
		///<summary>
		/// Temp speed change   
		///</summary>
		public int fast
		{
			get { return _fast; }
			set
			{
				if (value == _fast) return;
				_fast = value;
				this.RaisePropertyChanged(() => this.fast);
			}
		}
		///<summary>
		/// Temp speed change   
		///</summary>
		public int slow
		{
			get { return _slow; }
			set
			{
				if (value == _slow) return;
				_slow = value;
				this.RaisePropertyChanged(() => this.slow);
			}
		}
		///<summary>
		/// Fear		       
		///</summary>
		public int afraid
		{
			get { return _afraid; }
			set
			{
				if (value == _afraid) return;
				_afraid = value;
				this.RaisePropertyChanged(() => this.afraid);
			}
		}
		///<summary>
		/// Poisoned	       
		///</summary>
		public int poisoned
		{
			get { return _poisoned; }
			set
			{
				if (value == _poisoned) return;
				_poisoned = value;
				this.RaisePropertyChanged(() => this.poisoned);
			}
		}
		///<summary>
		/// Hallucinate	       
		///</summary>
		public int image
		{
			get { return _image; }
			set
			{
				if (value == _image) return;
				_image = value;
				this.RaisePropertyChanged(() => this.image);
			}
		}
		///<summary>
		/// Protect VS evil     
		///</summary>
		public int protevil
		{
			get { return _protevil; }
			set
			{
				if (value == _protevil) return;
				_protevil = value;
				this.RaisePropertyChanged(() => this.protevil);
			}
		}
		///<summary>
		/// Increases AC	       
		///</summary>
		public int invuln
		{
			get { return _invuln; }
			set
			{
				if (value == _invuln) return;
				_invuln = value;
				this.RaisePropertyChanged(() => this.invuln);
			}
		}
		///<summary>
		/// Heroism	       
		///</summary>
		public int hero
		{
			get { return _hero; }
			set
			{
				if (value == _hero) return;
				_hero = value;
				this.RaisePropertyChanged(() => this.hero);
			}
		}
		///<summary>
		/// Super Heroism       
		///</summary>
		public int shero
		{
			get { return _shero; }
			set
			{
				if (value == _shero) return;
				_shero = value;
				this.RaisePropertyChanged(() => this.shero);
			}
		}
		///<summary>
		/// Blessed	       
		///</summary>
		public int blessed
		{
			get { return _blessed; }
			set
			{
				if (value == _blessed) return;
				_blessed = value;
				this.RaisePropertyChanged(() => this.blessed);
			}
		}
		///<summary>
		/// Timed heat resist   
		///</summary>
		public int resist_heat
		{
			get { return _resist_heat; }
			set
			{
				if (value == _resist_heat) return;
				_resist_heat = value;
				this.RaisePropertyChanged(() => this.resist_heat);
			}
		}
		///<summary>
		/// Timed cold resist   
		///</summary>
		public int resist_cold
		{
			get { return _resist_cold; }
			set
			{
				if (value == _resist_cold) return;
				_resist_cold = value;
				this.RaisePropertyChanged(() => this.resist_cold);
			}
		}
		///<summary>
		/// Timed see invisible 
		///</summary>
		public int detect_inv
		{
			get { return _detect_inv; }
			set
			{
				if (value == _detect_inv) return;
				_detect_inv = value;
				this.RaisePropertyChanged(() => this.detect_inv);
			}
		}
		///<summary>
		/// Timed teleport level
		///</summary>
		public int word_recall
		{
			get { return _word_recall; }
			set
			{
				if (value == _word_recall) return;
				_word_recall = value;
				this.RaisePropertyChanged(() => this.word_recall);
			}
		}
		///<summary>
		/// See warm creatures  
		///</summary>
		public int see_infra
		{
			get { return _see_infra; }
			set
			{
				if (value == _see_infra) return;
				_see_infra = value;
				this.RaisePropertyChanged(() => this.see_infra);
			}
		}
		///<summary>
		/// Timed infra vision  
		///</summary>
		public int tim_infra
		{
			get { return _tim_infra; }
			set
			{
				if (value == _tim_infra) return;
				_tim_infra = value;
				this.RaisePropertyChanged(() => this.tim_infra);
			}
		}
		///<summary>
		/// Can see invisible   
		///</summary>
		public bool see_inv
		{
			get { return _see_inv; }
			set
			{
				if (value == _see_inv) return;
				_see_inv = value;
				this.RaisePropertyChanged(() => this.see_inv);
			}
		}
		///<summary>
		/// Random teleportation
		///</summary>
		public bool teleport
		{
			get { return _teleport; }
			set
			{
				if (value == _teleport) return;
				_teleport = value;
				this.RaisePropertyChanged(() => this.teleport);
			}
		}
		///<summary>
		/// Never paralyzed     
		///</summary>
		public bool free_act
		{
			get { return _free_act; }
			set
			{
				if (value == _free_act) return;
				_free_act = value;
				this.RaisePropertyChanged(() => this.free_act);
			}
		}
		///<summary>
		/// Lower food needs    
		///</summary>
		public bool slow_digest
		{
			get { return _slow_digest; }
			set
			{
				if (value == _slow_digest) return;
				_slow_digest = value;
				this.RaisePropertyChanged(() => this.slow_digest);
			}
		}
		///<summary>
		/// Aggravate monsters  
		///</summary>
		public bool aggravate
		{
			get { return _aggravate; }
			set
			{
				if (value == _aggravate) return;
				_aggravate = value;
				this.RaisePropertyChanged(() => this.aggravate);
			}
		}
		///<summary>
		/// Resistance to fire  
		///</summary>
		public bool fire_resist
		{
			get { return _fire_resist; }
			set
			{
				if (value == _fire_resist) return;
				_fire_resist = value;
				this.RaisePropertyChanged(() => this.fire_resist);
			}
		}
		///<summary>
		/// Resistance to cold  
		///</summary>
		public bool cold_resist
		{
			get { return _cold_resist; }
			set
			{
				if (value == _cold_resist) return;
				_cold_resist = value;
				this.RaisePropertyChanged(() => this.cold_resist);
			}
		}
		///<summary>
		/// Resistance to acid  
		///</summary>
		public bool acid_resist
		{
			get { return _acid_resist; }
			set
			{
				if (value == _acid_resist) return;
				_acid_resist = value;
				this.RaisePropertyChanged(() => this.acid_resist);
			}
		}
		///<summary>
		/// Regenerate hit pts  
		///</summary>
		public bool regenerate
		{
			get { return _regenerate; }
			set
			{
				if (value == _regenerate) return;
				_regenerate = value;
				this.RaisePropertyChanged(() => this.regenerate);
			}
		}
		///<summary>
		/// Resistance to light 
		///</summary>
		public bool lght_resist
		{
			get { return _lght_resist; }
			set
			{
				if (value == _lght_resist) return;
				_lght_resist = value;
				this.RaisePropertyChanged(() => this.lght_resist);
			}
		}
		///<summary>
		/// No damage falling   
		///</summary>
		public bool ffall
		{
			get { return _ffall; }
			set
			{
				if (value == _ffall) return;
				_ffall = value;
				this.RaisePropertyChanged(() => this.ffall);
			}
		}
		///<summary>
		/// Keep strength       
		///</summary>
		public bool sustain_str
		{
			get { return _sustain_str; }
			set
			{
				if (value == _sustain_str) return;
				_sustain_str = value;
				this.RaisePropertyChanged(() => this.sustain_str);
			}
		}
		///<summary>
		/// Keep intelligence   
		///</summary>
		public bool sustain_int
		{
			get { return _sustain_int; }
			set
			{
				if (value == _sustain_int) return;
				_sustain_int = value;
				this.RaisePropertyChanged(() => this.sustain_int);
			}
		}
		///<summary>
		/// Keep wisdom	       
		///</summary>
		public bool sustain_wis
		{
			get { return _sustain_wis; }
			set
			{
				if (value == _sustain_wis) return;
				_sustain_wis = value;
				this.RaisePropertyChanged(() => this.sustain_wis);
			}
		}
		///<summary>
		/// Keep constitution   
		///</summary>
		public bool sustain_con
		{
			get { return _sustain_con; }
			set
			{
				if (value == _sustain_con) return;
				_sustain_con = value;
				this.RaisePropertyChanged(() => this.sustain_con);
			}
		}
		///<summary>
		/// Keep dexterity      
		///</summary>
		public bool sustain_dex
		{
			get { return _sustain_dex; }
			set
			{
				if (value == _sustain_dex) return;
				_sustain_dex = value;
				this.RaisePropertyChanged(() => this.sustain_dex);
			}
		}
		///<summary>
		/// Keep charisma       
		///</summary>
		public bool sustain_chr
		{
			get { return _sustain_chr; }
			set
			{
				if (value == _sustain_chr) return;
				_sustain_chr = value;
				this.RaisePropertyChanged(() => this.sustain_chr);
			}
		}
		///<summary>
		/// Glowing hands.    
		///</summary>
		public int confuse_monster
		{
			get { return _confuse_monster; }
			set
			{
				if (value == _confuse_monster) return;
				_confuse_monster = value;
				this.RaisePropertyChanged(() => this.confuse_monster);
			}
		}
		///<summary>
		/// Number of spells can learn. 
		///</summary>
		public int new_spells
		{
			get { return _new_spells; }
			set
			{
				if (value == _new_spells) return;
				_new_spells = value;
				this.RaisePropertyChanged(() => this.new_spells);
			}
		}

		#endregion Flags

		public int pack_heavy
		{
			get { return this._packHeavy; }
			set
			{
				if (this._packHeavy == value) return;
				this._packHeavy = value;
				this.RaisePropertyChanged(() => this.pack_heavy);
			}
		}

		public bool isSearching { get { return this.Has(Status.SEARCH); } }
		public bool isResting { get { return this.rest != 0; } }
		public bool IsConfused { get { return this.confused > 0; } }
		public bool IsBlind { get { return this.blind > 0; } }
		public bool IsHero { get { return this.Has(Status.HERO); } }
		public bool IsSuperHero { get { return this.Has(Status.SHERO); } }
		public bool IsMage { get { return this.Class == null ? false : this.Class.spell == MajikType.Mage; } }
		public bool IsPriest { get { return this.Class == null ? false : this.Class.spell == MajikType.Priest; } }
		public bool IsGenerated { get; set; }
		public string Title { get { return this.GetTitle(); } }
		///<summary>
		/// find_flag    
		///</summary>
		public bool findFlag
		{
			get { return _findFlag; }
			set
			{
				if (value == _findFlag) return;
				_findFlag = value;
				this.RaisePropertyChanged(() => this.findFlag);
			}
		}
		///<summary>
		/// command_count	       
		///</summary>
		public int commandCount
		{
			get { return _commandCount; }
			set
			{
				if (value == _commandCount) return;
				_commandCount = value;
				this.RaisePropertyChanged(() => this.commandCount);
			}
		}
		public string Str { get { return this.cur_stat[Stat.A_STR].cnv_stat(); } }
		public string Int { get { return this.cur_stat[Stat.A_INT].cnv_stat(); } }
		public string Wis { get { return this.cur_stat[Stat.A_WIS].cnv_stat(); } }
		public string Dex { get { return this.cur_stat[Stat.A_DEX].cnv_stat(); } }
		public string Con { get { return this.cur_stat[Stat.A_CON].cnv_stat(); } }
		public string Chr { get { return this.cur_stat[Stat.A_CHR].cnv_stat(); } }
		// for adjusting prices
		public int chr_adj
		{
			get
			{

				int charisma = this.use_stat[Stat.A_CHR];
				if (charisma > 117) return (90);
				if (charisma > 107) return (92);
				if (charisma > 87) return (94);
				if (charisma > 67) return (96);
				if (charisma > 18) return (98);

				switch (charisma)
				{
					case 18: return (100);
					case 17: return (101);
					case 16: return (102);
					case 15: return (103);
					case 14: return (104);
					case 13: return (106);
					case 12: return (108);
					case 11: return (110);
					case 10: return (112);
					case 9: return (114);
					case 8: return (116);
					case 7: return (118);
					case 6: return (120);
					case 5: return (122);
					case 4: return (125);
					case 3: return (130);
					default: return (100);
				}
			}
		}
		public InventoryCollection inventory { get; private set; }
		public int CurrentDungeonLevel { get; set; }
		public int weight_limit
		{
			get
			{
				int weight_cap = this.use_stat[Stat.A_STR] * Player.WeightCap + this.wt;
				if (weight_cap > 3000) weight_cap = 3000;
				return (weight_cap);

			}
		}
		public int inven_weight
		{
			get { return this._invenWeight; }
			set
			{
				if (value == _invenWeight) return;
				_invenWeight = value;
				this.RaisePropertyChanged(() => this.inven_weight);
			}
		}

		#endregion Properties

		#region Events

		public event EventHandler<EventArgs> OnSpeedChanged;
		public event EventHandler<EventArgs> OnCheckView;

		protected override bool OnPropertyChanged(PropertyChangedEventArgs args)
		{
			switch (args.PropertyName)
			{
				case "hitdie": InitHitPoints(); break;
				case "prace": this.UpdateRacial(); break;
				case "pclass": this.UpdateClass(); break;
			}

			return base.OnPropertyChanged(args);
		}

		void MaxStat_Updated(object sender, StatChangedEventArgs e)
		{
			//TODO: implement MaxStat_Updated
		}
		void CurStat_Updated(object sender, StatChangedEventArgs e)
		{
			//TODO: implement CurStat_Updated

		}
		void ModStat_Updated(object sender, StatChangedEventArgs e)
		{
			//TODO: implement ModStat_Updated
		}
		void UseStat_Updated(object sender, StatChangedEventArgs e)
		{
			if (e.Stat == Stat.A_CON) this.InitHitPoints();
		}

		#endregion Events

		#region Methods

		public override string GetDescription()
		{
			return "there you are!";
		}
		private string GetTitle()
		{

			if (this.lev < 1) return "Babe in arms";
			else if (this.lev <= Player.MaxLevel) return player_title[this.pclass, this.lev - 1];
			else if (this.isMale) return "**KING**";
			return "**QUEEN**";
		}

		public Status Add(Status status) { return this.status.Add(status); }
		public Status Remove(Status status) { return this.status.Remove(status); }
		public bool Has(Status status) { return this.status.Has(status); }

		private bool UpdateClass()
		{
			if (this.pclass < 0 || this.prace >= Moria.Class.Table.Length) return false;
			this.Class = Class.Table[this.pclass];
			if (this.Class == null) return false;


			this.hitdie = this.Class.adj_hd;
			if (this.Race != null) this.hitdie += this.Race.bhitdie;

			this.bth += this.Class.mbth;
			this.bthb += this.Class.mbthb;	/*RAK*/
			this.srh += this.Class.msrh;
			this.disarm += this.Class.mdis;
			this.fos += this.Class.mfos;
			this.stl += this.Class.mstl;
			this.save += this.Class.msav;
			this.expfact += this.Class.m_exp;


			return true;
		}
		private bool UpdateRacial()
		{
			if (this.prace < 0 || this.prace >= Moria.Race.Table.Count()) return false;
			this.Race = Race.Table[this.prace];
			if (this.Race == null) return false;
			this.hitdie = this.Race.bhitdie;
			if (this.Class != null) this.hitdie += this.Class.adj_hd;
			this.srh = this.Race.srh;
			this.bth = this.Race.bth;
			this.bthb = this.Race.bthb;
			this.fos = this.Race.fos;
			this.stl = this.Race.stl;
			this.save = this.Race.bsav;
			this.expfact = this.Race.b_exp;
			this.see_infra = this.Race.infra;
			return true;
		}

		/* Set the value of the stat which is actually used.	 -CJS- */
		public void set_use_stat(Stat stat)
		{

			this.use_stat[stat] = modify_stat(stat, this.mod_stat[stat]);

			if (stat == Stat.A_STR)
			{
				//TODO: why are we adding this?
				this.Add(Status.STR_WGT);
				calc_bonuses();
			}
			else if (stat == Stat.A_DEX)
			{
				calc_bonuses();
			}
			else if (stat == Stat.A_INT || stat == Stat.A_WIS)
			{
				calc_spells();
				calc_mana();
			}
			else if (stat == Stat.A_CON)
			{
				calc_hitpoints();
			}
		}

		private bool InitHitPoints()
		{
			if (this.Race == null || this.Class == null) return false;

			if (this.hitdie != Race.bhitdie + this.Class.adj_hd)
				this.hitdie = Race.bhitdie + this.Class.adj_hd;

			if (this.player_hp == null)
				this.player_hp = new int[MaxLevel];

			this.mhp = this.con_adj() + this.hitdie;
			this.chp = this.mhp;
			this.chp_frac = 0;


			/* initialize hit_points array */
			/* put bounds on total possible hp, only succeed if it is within 1/8 of average value */
			int min_value = (MaxLevel * 3 / 8 * (this.hitdie - 1)) + MaxLevel;
			int max_value = (MaxLevel * 5 / 8 * (this.hitdie - 1)) + MaxLevel;
			player_hp[0] = this.mhp;
			do
			{
				for (int i = 1; i < MaxLevel; i++)
				{
					player_hp[i] = Dice.RandInt(this.hitdie);
					player_hp[i] += player_hp[i - 1];
				}
			}
			while ((player_hp[MaxLevel - 1] < min_value) || (player_hp[MaxLevel - 1] > max_value));
			return true;
		}

		private void calc_hitpoints()
		{
			if (this.player_hp == null && this.InitHitPoints())
			{
				int hitpoints = player_hp[this.lev - 1] + (con_adj() * this.lev);
				/* always give at least one point per level + 1 */
				if (hitpoints < (this.lev + 1))
					hitpoints = this.lev + 1;

				if (this.IsHero) hitpoints += 10;
				if (this.IsSuperHero) hitpoints += 20;

				/* mhp can equal zero while character is being created */
				if ((hitpoints != this.mhp) && (this.mhp != 0))
				{
					/* change current hit points proportionately to change of mhp,
				 //divide first to avoid overflow, little loss of accuracy */
					int value = ((this.chp << 16) + this.chp_frac) / this.mhp * hitpoints;
					this.chp = value >> 16;
					this.chp_frac = value & 0xFFFF;
					this.mhp = hitpoints;

					/* can't print hit points here, may be in store or this.inventory mode */
					this.Add(Status.HP);
				}
			}
		}

		private void calc_mana()
		{
			if (!IsMage || !IsPriest) return;
			Stat stat = this.IsMage ? Stat.A_INT : Stat.A_WIS;
			if (spell_learned != 0)
			{
				int levels = this.lev - this.Class.first_spell_lev + 1;
				int new_mana = 0;
				switch (stat_adj(stat))
				{
					case 1:
					case 2: new_mana = 1 * levels; break;
					case 3: new_mana = 3 * levels / 2; break;
					case 4: new_mana = 2 * levels; break;
					case 5: new_mana = 5 * levels / 2; break;
					case 6: new_mana = 3 * levels; break;
					case 7: new_mana = 4 * levels; break;
				}
				/* increment mana by one, so that first level chars have 2 mana */
				if (new_mana > 0) new_mana++;

				/* mana can be zero when creating character */
				if (this.mana != new_mana)
				{
					if (this.mana != 0)
					{
						/* change current mana proportionately to change of max mana,
					 divide first to avoid overflow, little loss of accuracy */
						int value = ((this.cmana << 16) + this.cmana_frac) / this.mana * new_mana;
						this.cmana = value >> 16;
						this.cmana_frac = value & 0xFFFF;
					}
					else
					{
						this.cmana = new_mana;
						this.cmana_frac = 0;
					}
					this.mana = new_mana;
					/* can't print mana here, may be in store or this.inventory mode */
					this.Add(Status.MANA);
				}
			}
			else if (this.mana != 0)
			{
				this.mana = 0;
				this.cmana = 0;
				/* can't print mana here, may be in store or this.inventory mode */
				this.Add(Status.MANA);
			}
		}

		private void calc_spells()
		{
			if (!IsPriest && !IsMage) return;
			Stat stat = this.IsPriest ? Stat.A_WIS : Stat.A_INT;
			MagicSpell[] spell = MagicSpell.Table[this.pclass - 1];
			string p = "prayer";
			//        int offset = PRAYER_OFFSET;
			if (stat == Stat.A_INT)
			{
				p = "spell";
				//offset = SPELL_OFFSET;
			}

			/* check to see if know any spells greater than level, eliminate them */
			for (uint i = 31, mask = 0x80000000; mask != 0; mask >>= 1, i--)
				if (spell_learned.HasBit(mask))
				{
					if (spell[i].slevel > this.lev)
					{
						spell_learned = spell_learned.RemoveBit(mask);
						spell_forgotten = spell_forgotten.SetBit(mask);
						this.Message("You have forgotten the {0} of {1}.", p, spell[i].Name);
					}
					else
						break;
				}

			/* calc number of spells allowed */
			int levels = this.lev - this.Class.first_spell_lev + 1;
			int num_allowed = 0;
			switch (stat_adj(stat))
			{
				case 1:
				case 2:
				case 3: num_allowed = 1 * levels; break;
				case 4:
				case 5: num_allowed = 3 * levels / 2; break;
				case 6: num_allowed = 2 * levels; break;
				case 7: num_allowed = 5 * levels / 2; break;
			}

			int num_known = 0;
			for (int mask = 0x1; mask != 0; mask <<= 1)
				if (spell_learned.HasBit(mask))
					num_known++;
			new_spells = num_allowed - num_known;

			if (new_spells > 0)
			{
				/* remember forgotten spells while forgotten spells exist of new_spells	 positive, remember the spells in the order that they were learned */
				for (int i = 0; (spell_forgotten != 0 && new_spells != 0 && (i < num_allowed) && (i < 32)); i++)
				{
					/* j is (i+1)th spell learned */
					int j = spell_order[i];
					/* shifting by amounts greater than number of bits in long gives
						 an undefined result, so don't shift for unknown spells */
					int mask = (j == 99) ? 0x0 : 1 << j;
					if (spell_forgotten.HasBit(mask))
					{
						if (spell[j].slevel <= this.lev)
						{
							new_spells--;
							spell_forgotten &= ~mask;
							spell_learned |= mask;
							this.Message("You have remembered the {0} of {1}.", p, spell[j].Name);
						}
						else
							num_allowed++;
					}
				}

				if (new_spells > 0)
				{
					/* determine which spells player can learn */
					/* must check all spells here, in gain_spell() we actually check
						 if the books are present */
					int spell_flag = 0x7FFFFFFF.RemoveBit(spell_learned);


					int i = 0;
					for (int j = 0, mask = 0x1; spell_flag != 0; mask <<= 1, j++)
						if (mask.HasBit(spell_flag))
						{
							spell_flag = spell_flag.RemoveBit(mask);
							if (spell[j].slevel <= this.lev)
								i++;
						}

					if (new_spells > i)
						new_spells = i;
				}
			}
			else if (new_spells < 0)
			{
				/* forget spells until new_spells zero or no more spells know, spells
			 are forgotten in the opposite order that they were learned */
				for (int i = 31; new_spells != 0 && spell_learned != 0; i--)
				{
					/* j is the (i+1)th spell learned */
					int j = spell_order[i];
					/* shifting by amounts greater than number of bits in long gives
						 an undefined result, so don't shift for unknown spells */
					int mask = (j == 99) ? 0x0 : 1 << j;
					if (spell_learned.HasBit(mask))
					{
						spell_learned = spell_learned.RemoveBit(mask);
						spell_forgotten = spell_forgotten.Add(mask);
						new_spells++;
						this.Message("You have forgotten the {0} of {1}.", p, spell[j]);

					}
				}

				new_spells = 0;
			}

			if (new_spells != this.new_spells)
			{
				if (new_spells > 0 && this.new_spells == 0)
				{
					this.Message("You can learn some new {0}s now.", p);
				}

				this.new_spells = new_spells;
				this.Add(Status.STUDY);
			}
		}

		private void calc_bonuses()
		{
			if (this.slow_digest) this.food_digested++;
			if (this.regenerate) this.food_digested -= 3;
			this.see_inv = false;
			this.teleport = false;
			this.free_act = false;
			this.slow_digest = false;
			this.aggravate = false;
			this.sustain_str = false;
			this.sustain_int = false;
			this.sustain_wis = false;
			this.sustain_con = false;
			this.sustain_dex = false;
			this.sustain_chr = false;
			this.fire_resist = false;
			this.acid_resist = false;
			this.cold_resist = false;
			this.regenerate = false;
			this.lght_resist = false;
			this.ffall = false;

			int old_dis_ac = this.dis_ac;
			this.ptohit = tohit_adj();	      /* Real To Hit   */
			this.ptodam = todam_adj();	      /* Real To Dam   */
			this.ptoac = toac_adj();	      /* Real To AC    */
			this.pac = 0;		    /* Real AC	     */
			this.dis_th = this.ptohit;  /* Display To Hit	    */
			this.dis_td = this.ptodam;  /* Display To Dam	    */
			this.dis_ac = 0;		/* Display AC		 */
			this.dis_tac = this.ptoac;   /* Display To AC	    */
			for (InventoryLocation i = InventoryLocation.Wield; i < InventoryLocation.Light; i++)
			{
				InventoryItem i_ptr = this.inventory[i];
				if (i_ptr == null || i_ptr.Type != ItemType.NOTHING) continue;
				this.ptohit += i_ptr.ToHit;
				if (i_ptr.Type != ItemType.BOW)		/* Bows can't damage. -CJS- */
					this.ptodam += i_ptr.ToDamage;
				this.ptoac += i_ptr.ToArmorClass;
				this.pac += i_ptr.Cost;
				if (i_ptr.IsKnown2)
				{
					this.dis_th += i_ptr.ToHit;
					if (i_ptr.Type != ItemType.BOW)
						this.dis_td += i_ptr.ToDamage;	/* Bows can't damage. -CJS- */
					this.dis_tac += i_ptr.ToArmorClass;
					this.dis_ac += i_ptr.ArmorClass;
				}
				else if (!i_ptr.IsCursed)
				{
					/* Base AC values should always be visible, as long as the item
						 is not cursed.  */
					this.dis_ac += i_ptr.ArmorClass;
				}

			}
			this.dis_ac += this.dis_tac;

			if (weapon_heavy)
				this.dis_th += (this.use_stat[Stat.A_STR] * 15 - this.inventory[InventoryLocation.Wield].Weight);

			/* Add in temporary spell increases	*/
			if (this.invuln > 0)
			{
				this.pac += 100;
				this.dis_ac += 100;
			}
			if (this.blessed > 0)
			{
				this.pac += 2;
				this.dis_ac += 2;
			}
			if (this.detect_inv > 0)
				this.see_inv = true;

			/* can't print AC here because might be in a store */
			if (old_dis_ac != this.dis_ac)
				this.Add(Status.ARMOR);

			ItemFlag item_flags = ItemFlag.NULL;
			for (InventoryLocation i = InventoryLocation.Wield; i < InventoryLocation.Light; i++)
			{
				InventoryItem i_ptr = this.inventory[i];
				if (i_ptr == null) continue;
				item_flags |= this.inventory[i].Flags;
			}
			if (item_flags.Has(ItemFlag.SLOW_DIGEST)) this.slow_digest = true;
			if (item_flags.Has(ItemFlag.AGGRAVATE)) this.aggravate = true;
			if (item_flags.Has(ItemFlag.TELEPORT)) this.teleport = true;
			if (item_flags.Has(ItemFlag.REGEN)) this.regenerate = true;
			if (item_flags.Has(ItemFlag.RES_FIRE)) this.fire_resist = true;
			if (item_flags.Has(ItemFlag.ResistAcid)) this.acid_resist = true;
			if (item_flags.Has(ItemFlag.RES_COLD)) this.cold_resist = true;
			if (item_flags.Has(ItemFlag.FREE_ACT)) this.free_act = true;
			if (item_flags.Has(ItemFlag.SEE_INVIS)) this.see_inv = true;
			if (item_flags.Has(ItemFlag.RES_LIGHT)) this.lght_resist = true;
			if (item_flags.Has(ItemFlag.FFALL)) this.ffall = true;


			for (InventoryLocation i = InventoryLocation.Wield; i < InventoryLocation.Light; i++)
			{
				InventoryItem i_ptr = this.inventory[i];
				if (i_ptr == null) continue;
				if (this.inventory[i].IsSustainStr) this.sustain_str = true;
				if (this.inventory[i].IsSustainInt) this.sustain_str = true;
				if (this.inventory[i].IsSustainWis) this.sustain_str = true;
				if (this.inventory[i].IsSustainCon) this.sustain_str = true;
				if (this.inventory[i].IsSustainChr) this.sustain_str = true;
				if (this.inventory[i].IsSustainDex) this.sustain_str = true;
			}

			if (this.slow_digest) this.food_digested--;
			if (this.regenerate) this.food_digested += 3;
		}

		/* Adjustment for wisdom/intelligence				-JWT-	*/
		private int stat_adj(Stat stat)
		{

			int value = this.use_stat[stat];
			if (value > 117) return (7);
			if (value > 107) return (6);
			if (value > 87) return (5);
			if (value > 67) return (4);
			if (value > 17) return (3);
			if (value > 14) return (2);
			if (value > 7) return (1);
			return (0);
		}

		private int con_adj()
		{
			int con = this.use_stat[Stat.A_CON];
			if (con < 7) return (con - 7);
			if (con < 17) return (0);
			if (con == 17) return (1);
			if (con < 94) return (2);
			if (con < 117) return (3);
			return (4);
		}

		/* Returns a character's adjustment to hit.		 -JWT-	 */
		private int tohit_adj()
		{

			int stat = this.use_stat[Stat.A_DEX];
			int total = 0;
			if (stat < 4) total = -3;
			if (stat < 6) total = -2;
			if (stat < 8) total = -1;
			if (stat < 16) total = 0;
			if (stat < 17) total = 1;
			if (stat < 18) total = 2;
			if (stat < 69) total = 3;
			if (stat < 118) total = 4;
			total = 5;
			stat = this.use_stat[Stat.A_STR];
			if (stat < 4) total -= 3;
			if (stat < 5) total -= 2;
			if (stat < 7) total -= 1;
			if (stat < 18) total -= 0;
			if (stat < 94) total += 1;
			if (stat < 109) total += 2;
			if (stat < 117) total += 3;
			total += 4;
			return (total);
		}

		/* Returns a character's adjustment to armor class	 -JWT-	 */
		private int toac_adj()
		{

			int stat = this.use_stat[Stat.A_DEX];
			if (stat < 4) return (-4);
			if (stat == 4) return (-3);
			if (stat == 5) return (-2);
			if (stat == 6) return (-1);
			if (stat < 15) return (0);
			if (stat < 18) return (1);
			if (stat < 59) return (2);
			if (stat < 94) return (3);
			if (stat < 117) return (4);
			return (5);
		}

		/* Returns a character's adjustment to disarm		 -RAK-	 */
		private int todis_adj()
		{

			int stat = this.use_stat[Stat.A_DEX];
			if (stat < 3) return (-8);
			if (stat == 4) return (-6);
			if (stat == 5) return (-4);
			if (stat == 6) return (-2);
			if (stat == 7) return (-1);
			if (stat < 13) return (0);
			if (stat < 16) return (1);
			if (stat < 18) return (2);
			if (stat < 59) return (4);
			if (stat < 94) return (5);
			if (stat < 117) return (6);
			return (8);
		}

		/* Returns a character's adjustment to damage		 -JWT-	 */
		private int todam_adj()
		{

			int stat = this.use_stat[Stat.A_STR];
			if (stat < 4) return (-2);
			if (stat < 5) return (-1);
			if (stat < 16) return (0);
			if (stat < 17) return (1);
			if (stat < 18) return (2);
			if (stat < 94) return (3);
			if (stat < 109) return (4);
			if (stat < 117) return (5);
			return (6);
		}

		private int modify_stat(Stat stat, int amount)
		{
			int tmp_stat = this.cur_stat[stat];
			int loop = (amount < 0 ? -amount : amount);
			for (int i = 0; i < loop; i++)
			{
				if (amount > 0)
				{
					if (tmp_stat < 18) tmp_stat++;
					else if (tmp_stat < 108) tmp_stat += 10;
					else tmp_stat = 118;
				}
				else
				{
					if (tmp_stat > 27) tmp_stat -= 10;
					else if (tmp_stat > 18) tmp_stat = 18;
					else if (tmp_stat > 3) tmp_stat--;
				}
			}
			return tmp_stat;
		}

		private InventoryItem FindItem(InventoryItem t_ptr)
		{
			InventoryItem invenItem = (this.inventory.FirstOrDefault(itm => (itm.Type == t_ptr.Type &&
																	itm.SubCategory == t_ptr.SubCategory &&
																	(itm.ItemCount + t_ptr.ItemCount < 256) &&
																	(t_ptr.SubCategory < InventoryItem.ITEM_GROUP_MIN || itm.Misc == t_ptr.Misc) &&
																	(itm.Known1 == t_ptr.Known1))));
			return invenItem;
		}
		internal bool inven_check_num(InventoryItem t_ptr)
		{
			if (this.inventory.Count < InventoryCollection.MaxSize) return true;

			if (this.FindItem(t_ptr) != null)
			{
				return true;
			};

			return false;
		}
		internal bool inven_check_weight(InventoryItem i_ptr)
		{
			int i = this.weight_limit;
			int new_inven_weight = i_ptr.ItemCount * i_ptr.Weight + this.inven_weight;
			if (i < new_inven_weight) i = new_inven_weight / (i + 1);
			else i = 0;

			if (this.pack_heavy != i) return false;

			return true;
		}
		public int inven_damage(Func<InventoryItem, bool> typ, int perc)
		{
			int result = -1;
			for (int ndx = 0; ndx < this.inventory.Count; ndx++)
			{
				InventoryItem itm = this.inventory[ndx];
				if (typ.Invoke(itm) && Dice.RandInt(100) < perc)
				{
					this.inven_destroy(itm);
					result = ndx;
				}
			}
			return result;
		}
		private void inven_destroy(InventoryItem i_ptr)
		{
			if ((i_ptr.ItemCount > 1) && (i_ptr.SubCategory <= InventoryItem.ITEM_SINGLE_STACK_MAX))
			{
				i_ptr.ItemCount--;
				inven_weight -= i_ptr.Weight;
			}
			else
			{
				inven_weight -= i_ptr.Weight * i_ptr.ItemCount;
				this.inventory.Remove(i_ptr);
			}

			this.Add(Status.STR_WGT);
		}

		internal int inven_carry(InventoryItem t_ptr)
		{
			int locn = -1;

			InventoryItem invenItem = this.FindItem(t_ptr);
			if (invenItem != null)
			{
				locn = this.inventory.IndexOf(invenItem);
				invenItem.ItemCount += t_ptr.ItemCount;
			}
			else
			{
				locn = this.inventory.Add(t_ptr);
				this.inven_weight += (t_ptr.ItemCount * t_ptr.Weight);
			}


			return locn;
		}

		internal bool test_hit(int bth, int level, int pth, int ac, int attack_type)
		{

			this.disturb(true, false);

			int i = bth + pth * BTH_PLUS_ADJ + (level * this.Class.adj[attack_type]);
			/* pth could be less than 0 if player wielding weapon too heavy for him */
			/* always miss 1 out of 20, always hit 1 out of 20 */
			int die = Dice.RandInt(20);
			return ((die != 1) && ((die == 20) || ((i > 0) && (Dice.RandInt(i) > ac))));  /* normal hit */
		}

		private void disturb(bool s, bool l)
		{
			this.commandCount = 0;
			if (s && this.isSearching) search_off();
			if (this.isResting) rest_off();
			if (l || this.findFlag)
			{
				this.findFlag = false;
				check_view();   // TODO: do we need this?
			}

		}

		private void rest_off()
		{
			this.rest = 0;
			this.Remove(Status.REST);
			this.food_digested++;
		}

		private void search_off()
		{
			check_view();
			change_speed(-1);
			this.Remove(Status.SEARCH);
			this.food_digested--;
		}

		private void change_speed(int num)
		{
			this.speed += num;
			this.Add(Status.SPEED);

			if (this.OnSpeedChanged != null)
				this.OnSpeedChanged.Invoke(this, new EventArgs());
		}

		private void check_view()
		{
			if (this.OnCheckView != null)
			{
				this.OnCheckView.Invoke(this, new EventArgs());
			}
		}
		public bool dec_stat(Stat stat)
		{
			int tmp_stat = this.cur_stat[stat];
			if (tmp_stat > 3)
			{
				if (tmp_stat < 19)
				{
					tmp_stat--;
				}
				else if (tmp_stat < 117)
				{
					int loss = (((118 - tmp_stat) >> 1) + 1) >> 1;
					tmp_stat += -Dice.RandInt(loss) - loss;
					if (tmp_stat < 18) tmp_stat = 18;
				}
				else
				{
					tmp_stat--;
				}
				this.cur_stat[stat] = tmp_stat;
				set_use_stat(stat);
				return true;
			}

			return false;
		}
		public bool minus_ac(ItemFlag typ_dam)
		{
			List<InventoryLocation> tmp = new List<InventoryLocation>();
			if (this.inventory[InventoryLocation.Body] != null) tmp.Add(InventoryLocation.Body);
			if (this.inventory[InventoryLocation.Arm] != null) tmp.Add(InventoryLocation.Arm);
			if (this.inventory[InventoryLocation.Outer] != null) tmp.Add(InventoryLocation.Outer);
			if (this.inventory[InventoryLocation.Hands] != null) tmp.Add(InventoryLocation.Hands);
			if (this.inventory[InventoryLocation.Head] != null) tmp.Add(InventoryLocation.Head);
			if (this.inventory[InventoryLocation.Feet] != null) tmp.Add(InventoryLocation.Feet);

			if (tmp.Count > 0)
			{
				InventoryLocation j = tmp[Dice.RandInt(tmp.Count) - 1];
				InventoryItem i_ptr = this.inventory[j];
				if (i_ptr.Has(typ_dam))
				{
					this.Message("Your {0} resists damage!", i_ptr.GetDescription(false));
					return true;
				}
				else if ((i_ptr.ArmorClass + i_ptr.ToArmorClass) > 0)
				{
					this.Message("Your {0} is damaged!", i_ptr.GetDescription(false));
					i_ptr.ToArmorClass--;
					calc_bonuses();
					return true;
				}
			}
			return false;
		}


		#endregion Methods

	}
}
